package com.shiyi.design.singleton;

import java.util.concurrent.TimeUnit;

/**
 * 懒汉式-双重检查+volatile
 * 只有在使用的时候，才会实例化对象，但是有线程安全的问题
 * 可以考虑在方法上加锁，由于是静态方法，锁的是SingletonDesignModel4.class对象
 * 但是效率不高，每次都要获取锁
 * 我们可以进行优化，减少锁的粒度，但是这次的写法，也会有线程安全的问题
 * 线程1先执行，进入判断后，线程2执行，也进入了判断，然后继续执行，实例化了对象，然后释放锁
 * 线程1执行，也会实例化对象
 *
 * 上述问题，我们可以通过double check进行解决
 *
 *  double check虽然解决了问题，但是因为指令重排序的问题，也会导致该方法返回的对象不完整，从而使用报错
 *  对象初始化基本分为以下几个步骤
 *      0 new #2 <com/shiyi/design/Test>    分配对象内存，内存地址压栈
 *      3 dup   复制一个内存地址栈帧
 *      4 invokespecial #3 <com/shiyi/design/Test.<init>>   内存地址弹栈，调用对象构造方法，初始化对象成员变量
 *      7 astore_1  内存地址弹栈，复制给本地变量表中的test变量
 *      8 return 结束
 *  正常情况下本来是顺序执行指令的，但是如果对指令进行重排序，那么可能会变成下面这样
 *      0 new #2 <com/shiyi/design/Test>    分配对象内存，内存地址压栈
 *      3 dup   复制一个内存地址栈帧
 *      7 astore_1  内存地址弹栈，复制给本地变量表中的test变量
 *      4 invokespecial #3 <com/shiyi/design/Test.<init>>   内存地址弹栈，调用对象构造方法，初始化对象成员变量
 *      8 return 结束
 *
 *  这就导致了，对象还没有初始化，就已经赋值了，然后其他线程判断INSTANCE != null直接返回使用了，肯定会报错的
 *  这个问题，其实正常生产环境下极其难以发生，所以我们其实可以不需要管的，但是需要知道这个问题
 *  使用volatile禁止指令重排序
 *
 * @Author qiu
 * @Date 2021/1/10 23:09
 */
public class SingletonDesignModel7 {

    private static volatile SingletonDesignModel7 INSTANCE = null;

    private SingletonDesignModel7(){};

    public static SingletonDesignModel7 getInstance() {
        if(INSTANCE == null) {
            System.out.println("1");
            synchronized(SingletonDesignModel7.class) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if(INSTANCE == null) {
                    INSTANCE = new SingletonDesignModel7();
                }
            }
        }
        return INSTANCE;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(() -> System.out.println(Thread.currentThread().getName() + "----" + SingletonDesignModel7.getInstance().hashCode())).start();
        }
    }
}
